package com.cloudfunx.common.util;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

/**
 * @author linjiayu
 */
public final class EncryptionUtils {

    /**
     * 指定为url safe模式
     */
    // private final static Base64 BASE64 = new Base64(true);
    private final static String UTF_8 = "utf-8";
    /**
     * 加密初始向量
     */
    private final static String IV = "htLVJIdy";
    /**
     * 加密的key
     */
    private final static String KEY = "HTljdAoyoU";

    /**
     * 加密字符串,对url是安全的
     *
     * @param str 原字符串
     * @return 加密后的字符串
     */
    public static String encryptString(String str) {
        if (StringUtils.isBlank(str)) {
            throw new RuntimeException("encrypt str must not null!");
        }
        try {
            // 对称加密
            byte[] encodeByte = symmetricEncrypt(str.getBytes(UTF_8), KEY);
            //加密后的字符串多了\r\n的结尾，这里移除对应的结尾
            return Base64Utils.encodeToUrlSafeString(encodeByte).replaceAll("\r\n", "");
            // return BASE64.encodeToString(encodeByte).replaceAll("\r\n", "");
        } catch (Exception e) {
            throw new RuntimeException("encrypt occur error", e);
        }

    }

    /**
     * 解密字符串，对url是安全的
     *
     * @param str 已加密的字符串
     * @return 解密后的字符串
     */
    public static String decryptString(String str) {
        if (StringUtils.isBlank(str)) {
            throw new RuntimeException("decrypt str must not null!");
        }

        // base64解码
        byte[] encodeByte = Base64Utils.decodeFromUrlSafeString(str);

        try {
            //解密
            byte[] decoderBytes = symmetricDecrypt(encodeByte, KEY);
            return new String(decoderBytes, UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("decrypt occur error", e);
        }

    }

    /**
     * 对称加密方法
     *
     * @param byteSource 需要加密的数据
     * @param sKey       key字符串
     * @return 经过加密的数据
     */
    public static byte[] symmetricEncrypt(byte[] byteSource, String sKey) throws Exception {
        int mode = Cipher.ENCRYPT_MODE;
        Key key = generateKey(sKey);
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        IvParameterSpec ips = new IvParameterSpec(IV.getBytes());
        cipher.init(mode, key, ips);
        return cipher.doFinal(byteSource);
    }

    /**
     * 根据key字符串生成加密的Key对象
     *
     * @param sKey
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidKeySpecException
     * @throws UnsupportedEncodingException
     */
    private static Key generateKey(String sKey) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, UnsupportedEncodingException {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        DESKeySpec keySpec = new DESKeySpec(sKey.getBytes(UTF_8));
        return keyFactory.generateSecret(keySpec);
    }

    /**
     * 对称解密方法
     *
     * @param byteSource 需要解密的数据
     * @param sKey       key字符串
     * @return 经过解密的数据
     */
    public static byte[] symmetricDecrypt(byte[] byteSource, String sKey) throws Exception {
        //将字节数组转化为输入流
        int mode = Cipher.DECRYPT_MODE;
        Key key = generateKey(sKey);
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        IvParameterSpec ips = new IvParameterSpec(IV.getBytes());
        cipher.init(mode, key, ips);
        return cipher.doFinal(byteSource);
    }

    /**
     * 解密二进制数据编码为BASE64字符串
     * 不是url safe
     * @param str 需要解密的字符串
     * @return 解密后的字符串
     */
    public static String decode(String str) throws UnsupportedEncodingException {
        byte[] bytes = str.getBytes(UTF_8);
        return new String(Base64Utils.decodeUrlSafe(bytes),UTF_8);
    }

    /**
     * 加密二进制数据编码为BASE64字符串
     * 不是url safe
     * @param str 需要加密的字符串
     * @return 加密后的字符串
     */
    public static String encode(String str) throws UnsupportedEncodingException {
        byte[] bytes = str.getBytes(UTF_8);
        return new String(Base64Utils.encodeUrlSafe(bytes),UTF_8);
    }
}
